/*
 * Copyright (c) 2006-2007 Erin Catto http://www.gphysics.com
 *
 * This software is provided 'as-is', without any express or implied
 * warranty.  In no event will the authors be held liable for any damages
 * arising from the use of this software.
 * Permission is granted to anyone to use this software for any purpose,
 * including commercial applications, and to alter it and redistribute it
 * freely, subject to the following restrictions:
 * 1. The origin of this software must not be misrepresented; you must not
 * claim that you wrote the original software. If you use this software
 * in a product, an acknowledgment in the product documentation would be
 * appreciated but is not required.
 * 2. Altered source versions must be plainly marked as such, and must not be
 * misrepresented as being the original software.
 * 3. This notice may not be removed or altered from any source distribution.
 */

package org.box2dflash.dynamics.joints {
	import org.box2dflash.dynamics.joints.DistanceJoint;
	import org.box2dflash.dynamics.Body;
	import org.box2dflash.common.math.Vec2;
	import org.box2dflash.common.math.*;
	import org.box2dflash.common.*;
	import org.box2dflash.dynamics.*;
	use namespace Internal;

	/// The base joint class. Joints are used to constraint two bodies together in
	/// various fashions. Some joints also feature limits and motors.
	
	public class Joint {
		/// Get the type of the concrete joint.
		public function get type():int {
			return m_type;
		}

		/// Get the anchor point on body1 in world coordinates.
		public  function get anchor1():Vec2 {
			return null;
		}

		/// Get the anchor point on body2 in world coordinates.
		public  function get anchor2():Vec2 {
			return null;
		}

		/// Get the reaction force on body2 at the joint anchor.
		public  function get reactionForce():Vec2 {
			return null;
		}

		/// Get the reaction torque on body2.
		public  function get reactionTorque():Number {
			return 0.0;
		}

		/// Get the first body attached to this joint.
		public function get body1():Body {
			return m_body1;
		}

		/// Get the second body attached to this joint.
		public function get body2():Body {
			return m_body2;
		}

		/// Get the next joint the world joint list.
		public function get next():Joint {
			return m_next;
		}

		/// Get the user data pointer.
		public function get userData():* {
			return m_userData;
		}

		/// Set the user data pointer.
		public function set UserData(data:*):void {
			m_userData = data;
		}

		//--------------- Internals Below -------------------
		static Internal function Create(def:JointDef/*NEVER USED , allocator:* */):Joint {
			var joint:Joint = null;
		
			switch (def.type) {
				case e_distanceJoint:
					{
				//void* mem = allocator->Allocate(sizeof(DistanceJoint));
				joint = new DistanceJoint(def as DistanceJointDef);
			}
					break;
		
		case e_mouseJoint:
			{
				//void* mem = allocator->Allocate(sizeof(MouseJoint));
				joint = new MouseJoint(def as MouseJointDef);
			}
			break;
		
		case e_prismaticJoint:
			{
				//void* mem = allocator->Allocate(sizeof(PrismaticJoint));
				joint = new PrismaticJoint(def as PrismaticJointDef);
			}
			break;
		
		case e_revoluteJoint:
			{
				//void* mem = allocator->Allocate(sizeof(RevoluteJoint));
				joint = new RevoluteJoint(def as RevoluteJointDef);
			}
			break;
		
		case e_pulleyJoint:
			{
				//void* mem = allocator->Allocate(sizeof(PulleyJoint));
				joint = new PulleyJoint(def as PulleyJointDef);
			}
			break;
		
		case e_gearJoint:
			{
				//void* mem = allocator->Allocate(sizeof(GearJoint));
				joint = new GearJoint(def as GearJointDef);
			}
			break;
		
		default:
			//Settings.Assert(false);
			break;
			}
		
			return joint;
		}
	
	static Internal function Destroy(joint:Joint/*NEVER USED , allocator:* */) : void{
		/*joint->~Joint();
		switch (joint.m_type)
		{
		case e_distanceJoint:
			allocator->Free(joint, sizeof(DistanceJoint));
			break;
		
		case e_mouseJoint:
			allocator->Free(joint, sizeof(MouseJoint));
			break;
		
		case e_prismaticJoint:
			allocator->Free(joint, sizeof(PrismaticJoint));
			break;
		
		case e_revoluteJoint:
			allocator->Free(joint, sizeof(RevoluteJoint));
			break;
		
		case e_pulleyJoint:
			allocator->Free(joint, sizeof(PulleyJoint));
			break;
		
		case e_gearJoint:
			allocator->Free(joint, sizeof(GearJoint));
			break;
		
		default:
			Assert(false);
			break;
		}*/
	}

	public function Joint(def:JointDef){
		m_type = def.type;
		m_prev = null;
		m_next = null;
		m_body1 = def.body1;
		m_body2 = def.body2;
		m_collideConnected = def.collideConnected;
		m_islandFlag = false;
		m_userData = def.userData;
	}
	//virtual ~Joint() {}

	Internal  function initVelocityConstraints(step:TimeStep) : void{};
	Internal  function solveVelocityConstraints(step:TimeStep) : void{};

	// This returns true if the position errors are within tolerance.
	Internal  function initPositionConstraints() : void{};
	Internal  function solvePositionConstraints():Boolean{return false;};

	Internal var m_type:int;
	Internal var m_prev:Joint;
	Internal var m_next:Joint;
	Internal var m_node1:JointEdge = new JointEdge();
	Internal var m_node2:JointEdge = new JointEdge();
	Internal var m_body1:Body;
	Internal var m_body2:Body;

	Internal var m_inv_dt:Number;

	Internal var m_islandFlag:Boolean;
	Internal var m_collideConnected:Boolean;

	Internal var m_userData:*;
	
	
	// ENUMS
	
	// enum JointType
	static public const e_unknownJoint:int = 0;
	static public const e_revoluteJoint:int = 1;
	static public const e_prismaticJoint:int = 2;
	static public const e_distanceJoint:int = 3;
	static public const e_pulleyJoint:int = 4;
	static public const e_mouseJoint:int = 5;
	static public const e_gearJoint:int = 6;

	// enum LimitState
	static public const e_inactiveLimit:int = 0;
	static public const e_atLowerLimit:int = 1;
	static public const e_atUpperLimit:int = 2;
	static public const e_equalLimits:int = 3;
	}
}
